package conservare.web;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;

import org.primefaces.context.RequestContext;
import org.primefaces.model.SelectableDataModel;

import conservare.modelo.contrato.Contrato;
import conservare.modelo.financeiro.ContaAReceber;
import conservare.modelo.type.Mes;
import conservare.negocio.ContaAReceberRN;
import conservare.negocio.ContratoRN;
import conservare.util.JSFUtil;

@ManagedBean
@ViewScoped
public class LancamentoContaAReceberBean implements Serializable {
	private static final long serialVersionUID = -2507217906050862988L;

	//private List<Contrato> contratos;
	private List<Contrato> contratosDisponiveisParaLancamentoNoMes;
	private List<Contrato> contratosFiltrados;
	private List<Contrato> contratosAtivos = new ArrayList<>();
	private ContaAReceber lancamento;
	
	private List<SelectItem> anosItens;
	private List<SelectItem> mesesItens;
	private Mes mesDeReferenciaSelecionado;
	private Integer anoDeReferenciaSelecionado;
	private Date dataDoVencimentoSelecionado;
	private ContratoDataModel contratosDataModel;
	private Contrato[] contratosSelecionados;
	private String mensagemNenhumContratoSelecionadoParaLancamento;
	
	public String doGerarLancamentosContasAReceber(){
		
		setMensagemNenhumContratoSelecionadoParaLancamento(null);
		
		if(getContratosSelecionados() == null || getContratosSelecionados().length == 0){
			setMensagemNenhumContratoSelecionadoParaLancamento("Selecione pelo menos 1 (um) Contrato !");
			return null;
		}else{
			
			for(int i = 0; i < getContratosSelecionados().length; i++){
				boolean contratoJaLacado = new ContaAReceberRN().isContratoJaLancado(getContratosSelecionados()[i], getAnoDeReferenciaSelecionado(), getMesDeReferenciaSelecionado());
				if(contratoJaLacado){
					JSFUtil.addInfoMessage("Conta a Receber do Contrato de número \"" + getContratosSelecionados()[i].getId() + "\" já foi lançado para "  + getMesDeReferenciaSelecionado() + " de " + getAnoDeReferenciaSelecionado() + " !");
					return null;
				}
			}
			
			for(int i = 0; i < getContratosSelecionados().length; i++){
				new ContaAReceberRN().salvar(new ContaAReceber(getContratosSelecionados()[i], getAnoDeReferenciaSelecionado(), getMesDeReferenciaSelecionado(), getDataDoVencimentoSelecionado()));
			}
			
			JSFUtil.addInfoMessage("Contas lançadas com sucesso !");
			
			return "contaareceberlistagem.xhtml";
		}
		
	}
	
	
	public void doConfirmarLancamento(ActionEvent actionEvent) {
		
		boolean isOk = true; 
		FacesMessage msg = null;
		
		if(getLancamento().getValorAPagar().doubleValue() == 0.0){
			msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Entre com o valor a receber !", null);
			isOk = false;
		}else{
			new ContaAReceberRN().salvar(getLancamento());
			msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Lançamento realizadom com sucesso !", null);
		}
		
		
		FacesContext.getCurrentInstance().addMessage(null, msg); 
		RequestContext context = RequestContext.getCurrentInstance(); 
		context.addCallbackParam("isOk", isOk);  
		
	}

	public String doPrepararLancamentoContaAReceber(Contrato contratoSelecionado){
		
		ContaAReceber lancamentoContaAReceber = new ContaAReceber(contratoSelecionado);
		setLancamento(lancamentoContaAReceber);
		
		return null;
	}
	
	public String doPesquisarContratosDisponiveisParaLancamentoNoMes(){
		
		setContratosDisponiveisParaLancamentoNoMes( new ContratoRN().getContratosDisponiveisParaLancamentoNoMes(this.anoDeReferenciaSelecionado, this.mesDeReferenciaSelecionado));
		if(getContratosDisponiveisParaLancamentoNoMes() != null && getContratosDisponiveisParaLancamentoNoMes().size() == 0){
			setContratosDisponiveisParaLancamentoNoMes(null);
		}
		
		return null;
		
	}
	
	
	
	
	public List<Contrato> getContratosAtivos() {
		if(this.contratosAtivos.size() == 0){
			this.contratosAtivos = new ContratoRN().getContratosAtivos();
		}
		return contratosAtivos;
	}

	/**
	 * Somente interessa os contratos para os quais ainda não houve lançamento para o ano/mês selecionado.
	 * @return
	 */
/*	public List<Contrato> getContratos() {
		if(contratos == null && anoEMesFoiSelecionadoPeloUsuario()){
			List<Contrato> contratosParaSeremDesconsiderados = new ContaAReceberRN().obterContratosParaOsQuaisHouveLancamentoNoAnoMes(getAnoDeReferenciaSelecionado(), getMesDeReferenciaSelecionado().getNumero());
			if(contratosParaSeremDesconsiderados != null && contratosParaSeremDesconsiderados.size() > 0)
				contratos = new ContratoRN().getTodosComExcecaoDestes(contratosParaSeremDesconsiderados);
			else
				contratos = new ContratoRN().getTodos();
			
			if(contratos != null && contratos.size() == 0)
				contratos = null;
			
		}
		return contratos;
	}*/
	
	
/*	public List<Contrato> getContratos() {
		contratos = new ContratoRN().getTodos();
		if(contratos != null && contratos.size() == 0)
			contratos = null;
		
		return contratos;
	}*/
	
	public List<Contrato> getContratosDisponiveisParaLancamentoNoMes() {
		
		return contratosDisponiveisParaLancamentoNoMes;
	}
	
	
	/*public void setContratos(List<Contrato> contratos) {
		this.contratos = contratos;
	}
*/

/*	public boolean isAnoEMesFoiSelecionadoPeloUsuario(){
		
		return getAnoDeReferenciaSelecionado() != null && getMesDeReferenciaSelecionado() != null;
		
	}*/

	
	public String getMesesDeLancamentosRecentes(){
		
		if(getLancamento() != null && getLancamento().getContrato() != null){
			int topN = 3;
			return new ContaAReceberRN().getMesesDeLancamentosRecentesDesteContrato(getLancamento().getContrato(), topN);
		}else{
			return " ";
		}
		
			
	}
	
	public List<SelectItem> getAnosItens() {
		//mostra esse ano anterior/ano atual/ano posterior
		if(anosItens == null){
			anosItens = new ArrayList<SelectItem>();
			Integer anoCorrente = Calendar.getInstance().get(Calendar.YEAR);
			Integer anoAnterior = anoCorrente - 1;
			Integer AnoSeguinte = anoCorrente + 1;
			this.anosItens.add(new SelectItem(anoAnterior, String.valueOf(anoAnterior)));//value - label
			this.anosItens.add(new SelectItem(anoCorrente, String.valueOf(anoCorrente)));//value - label
			this.anosItens.add(new SelectItem(AnoSeguinte, String.valueOf(AnoSeguinte)));//value - label
		}
		return anosItens;
	}
	
	public List<SelectItem> getMesesItens() {
		if(mesesItens == null){
			mesesItens = new ArrayList<SelectItem>();
			for (Mes item : Mes.values())
				this.mesesItens.add(new SelectItem(item,item.getDescricao()));//value - label
		}
		return mesesItens;
	}

	public Mes getMesDeReferenciaSelecionado() {
		return mesDeReferenciaSelecionado;
	}

	public void setMesDeReferenciaSelecionado(Mes mesDeReferenciaSelecionado) {
		this.mesDeReferenciaSelecionado = mesDeReferenciaSelecionado;
		setContratosDataModel(null);
		setContratosDisponiveisParaLancamentoNoMes(null);
	}


	public Integer getAnoDeReferenciaSelecionado() {
		return anoDeReferenciaSelecionado;
	}


	public void setAnoDeReferenciaSelecionado(Integer anoDeReferenciaSelecionado) {
		this.anoDeReferenciaSelecionado = anoDeReferenciaSelecionado;
		setContratosDataModel(null);
		setContratosDisponiveisParaLancamentoNoMes(null);
	}


	public List<Contrato> getContratosFiltrados() {
		return contratosFiltrados;
	}

	public void setContratosFiltrados(List<Contrato> contratosFiltrados) {
		this.contratosFiltrados = contratosFiltrados;
	}


	public Date getDataDoVencimentoSelecionado() {
		return dataDoVencimentoSelecionado;
	}

	public void setDataDoVencimentoSelecionado(Date dataDoVencimentoSelecionado) {
		this.dataDoVencimentoSelecionado = dataDoVencimentoSelecionado;
	}

	
	public void setContratosDisponiveisParaLancamentoNoMes(List<Contrato> contratosDisponiveisParaLancamentoNoMes) {
		this.contratosDisponiveisParaLancamentoNoMes = contratosDisponiveisParaLancamentoNoMes;
	}
	

	public String getMensagemNenhumContratoSelecionadoParaLancamento() {
		
		return mensagemNenhumContratoSelecionadoParaLancamento != null ? mensagemNenhumContratoSelecionadoParaLancamento : " ";
	}

	public void setMensagemNenhumContratoSelecionadoParaLancamento(String mensagemNenhumContratoSelecionadoParaLancamento) {
		this.mensagemNenhumContratoSelecionadoParaLancamento = mensagemNenhumContratoSelecionadoParaLancamento;
	}

	public ContratoDataModel getContratosDataModel() {
		
		if(getContratosDisponiveisParaLancamentoNoMes() != null && getContratosDisponiveisParaLancamentoNoMes().size() > 0)
			contratosDataModel = new ContratoDataModel(getContratosDisponiveisParaLancamentoNoMes());
		else
			contratosDataModel = null;
		
		return contratosDataModel;
	}


	public void setContratosDataModel(ContratoDataModel contratosDataModel) {
		this.contratosDataModel = contratosDataModel;
	}
	
	public Contrato[] getContratosSelecionados() {
		return contratosSelecionados;
	}


	public void setContratosSelecionados(Contrato[] contratosSelecionados) {
		this.contratosSelecionados = contratosSelecionados;
	}
	

		




	public ContaAReceber getLancamento() {
		return lancamento;
	}


	public void setLancamento(ContaAReceber lancamento) {
		this.lancamento = lancamento;
	}







	// InnerClass
	public class ContratoDataModel extends ListDataModel<Contrato> implements SelectableDataModel<Contrato> {

		public ContratoDataModel() {
		}

		public ContratoDataModel(List<Contrato> contratos) {
			super(contratos);
		}

		@Override
		public Contrato getRowData(String rowKey) {
			// In a real app, a more efficient way like a query by rowKey should
			// be implemented to deal with huge data

			@SuppressWarnings("unchecked")
			List<Contrato> contratos = (List<Contrato>) getWrappedData();

			for (Contrato contrato : contratos) {
				if (contrato.getId() == Integer.parseInt(rowKey)) {
					return contrato;
				}
			}

			return null;
		}

		@Override
		public Object getRowKey(Contrato contrato) {
			return contrato.getId();
		}
	}
}
